package org.rendao.biz.service.impl;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.hibernate.Criteria;
import org.hibernate.SessionFactory;
import org.hibernate.criterion.Criterion;
import org.hibernate.criterion.Restrictions;
import org.rendao.biz.data.QuestionDO;
import org.rendao.biz.model.Question;
import org.rendao.biz.model.QuestionCriteria;
import org.rendao.biz.model.report.QuestionReportEntity;
import org.rendao.biz.service.QuestionService;
import org.rendao.constant.ConstantDefinition;
import org.rendao.dao.IGenericDao;
import org.rendao.model.CommonSummary;
import org.rendao.model.query.CommonSummaryRowMapper;
import org.rendao.utils.AssembleUtils;
import org.rendao.utils.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
import org.springframework.transaction.annotation.Transactional;

public class QuestionServiceImpl implements QuestionService {

	private IGenericDao<QuestionDO> dao;

	public void setDao(IGenericDao<QuestionDO> daoToSet) {
		dao = daoToSet;
		dao.setClazz(QuestionDO.class);
	}

	@Autowired
	private NamedParameterJdbcTemplate jdbcTemplate;

	public void setJdbcTemplate(NamedParameterJdbcTemplate jdbcTemplate) {
		this.jdbcTemplate = jdbcTemplate;
	}

	@Autowired
	private SessionFactory sessionFactory;

	public void setSessionFactory(SessionFactory sessionFactory) {
		this.sessionFactory = sessionFactory;
	}

	@Override
	public Question getById(String id) {
		QuestionDO questionDO = dao.getById(id);
		return AssembleUtils.shadowCopy(questionDO, Question.class);
	}

	@Override
	public Question saveOrUpdate(Question question) {
		QuestionDO questionDO = AssembleUtils.shadowCopy(question,
				QuestionDO.class);
		QuestionDO resultDO = null;
		if (StringUtils.isNullOrEmpty(question.getId())) {
			resultDO = dao.save(questionDO);
		} else {
			resultDO = dao.update(questionDO);
		}
		return AssembleUtils.shadowCopy(resultDO, Question.class);
	}

	@SuppressWarnings("unchecked")
	@Transactional
	@Override
	public List<Question> search(QuestionCriteria criteria) {
		Criteria c = sessionFactory.getCurrentSession().createCriteria(
				QuestionDO.class);
		if (!StringUtils.isNullOrEmpty(criteria.getFirstIndexId())) {
			Criterion firstIndexCriteria = Restrictions.eq("firstIndexId",
					criteria.getFirstIndexId());
			c.add(firstIndexCriteria);
		}
		if (!StringUtils.isNullOrEmpty(criteria.getSecondIndexId())) {
			Criterion secondIndexCriteria = Restrictions.eq("secondIndexId",
					criteria.getSecondIndexId());
			c.add(secondIndexCriteria);
		}
		if (!StringUtils.isNullOrEmpty(criteria.getQuestionId())) {
			Criterion questionIdCriteria = Restrictions.eq("id",
					criteria.getQuestionId());
			c.add(questionIdCriteria);
		}
		if (!StringUtils.isNullOrEmpty(criteria.getUserId())) {
			Criterion userCriteria = Restrictions.eq("userId",
					criteria.getUserId());
			c.add(userCriteria);
		}
		if (!StringUtils.isNullOrEmpty(criteria.getStatus())) {
			Criterion statusCriteria = Restrictions.eq("status",
					criteria.getStatus());
			c.add(statusCriteria);
		}
		if (criteria.getReceiveDateFrom() != null) {
			Criterion receivedFromCriteria = Restrictions.ge("receivedDate",
					criteria.getReceiveDateFrom());
			c.add(receivedFromCriteria);
		}
		if (criteria.getReceiveDateTo() != null) {
			Criterion receivedToCriteria = Restrictions.le("receivedDate",
					criteria.getReceiveDateTo());
			c.add(receivedToCriteria);
		}
		if (!StringUtils.isNullOrEmpty(criteria.getFuzzyKeyword())) {
			Criterion questionCriteria = Restrictions.like("question", "%"
					+ criteria.getFuzzyKeyword() + "%");
			Criterion answerCriteria = Restrictions.like("answer", "%"
					+ criteria.getFuzzyKeyword() + "%");
			Criterion fuzzyCriteria = Restrictions.or(questionCriteria,
					answerCriteria);
			c.add(fuzzyCriteria);
		}
		Criterion isDeletedCriteria = Restrictions.eq("isDeleted",
				ConstantDefinition.IS_DELETED_FALSE);
		c.add(isDeletedCriteria);
		return AssembleUtils.shadowCopyList(c.list(), Question.class);
	}

	@Transactional
	@Override
	public List<QuestionReportEntity> getReportData(QuestionCriteria criteria) {
		List<Question> questions = search(criteria);
		List<String> questionIds = new ArrayList<String>();
		if (questions != null) {
			for (Question q : questions) {
				questionIds.add(q.getId());
			}
		}

		String sql = " select                                             "
				+ "        first_index.name as firstIndexName,         "
				+ "        question.received_date as receivedDate,     "
				+ "        user.displayname as userName,               "
				+ "        question.question as questionContent,       "
				+ "        question.answer as answerContent            "
				+ " from                                               "
				+ "        question,                                   "
				+ "        first_index,                                "
				+ "        user                                        "
				+ " where                                              "
				+ "        question.first_index_id = first_index.id and"
				+ "        question.user_id = user.id and              "
				+ "        question.is_deleted = 'F' and               "
				+ "        question.id in (:questionIds)               ";

		Map<String, Object> params = new HashMap<String, Object>();
		params.put("questionIds", questionIds);
		List<QuestionReportEntity> result = jdbcTemplate.query(sql, params,
				new QuestionReportRowMapper());
		return result;
	}

	@Transactional
	@Override
	public List<CommonSummary> getFirstIndexSummary() {
		String sql = "select                                     "
				+ "    first_index.name,                         "
				+ "    count(first_index.name)                   "
				+ "from                                          "
				+ "    first_index,                              "
				+ "    question                                  "
				+ "where                                         "
				+ "    question.first_index_id = first_index.id  "
				+ "group by                                      "
				+ "    first_index.name                          ";
		Map<String, Object> params = new HashMap<String, Object>();
		List<CommonSummary> result = jdbcTemplate.query(sql, params,
				new CommonSummaryRowMapper());
		return result;
	}
}

class QuestionReportRowMapper implements RowMapper<QuestionReportEntity> {
	@Override
	public QuestionReportEntity mapRow(ResultSet rs, int rowNum)
			throws SQLException {
		QuestionReportEntity entity = new QuestionReportEntity();
		entity.setFirstIndexName(rs.getString("firstIndexName"));
		entity.setReceivedDate(rs.getDate("receivedDate"));
		entity.setUserName(rs.getString("userName"));
		entity.setQuestionContent(rs.getString("questionContent"));
		entity.setAnswerContent(rs.getString("answerContent"));
		return entity;
	}
}
